package handlers

import (
	"bloggo/bloggo"
	"bloggo/dto"
	"bloggo/service"
	"bloggo/structs"
	"context"
	"encoding/json"
	"gitee.com/chunanyong/zorm"
	"github.com/gin-gonic/gin"
	"github.com/gomodule/redigo/redis"
	"io/ioutil"
	"strconv"
	"time"
)

// Comments 评论列表
func Comments(c *gin.Context) *bloggo.R {
	var data []*dto.Comment
	articleId := c.DefaultQuery("articleId", "")
	if articleId == "" {
		return bloggo.OkData(gin.H{
			"recordList": data,
			"count":      nil,
		})
	}

	page := zorm.NewPage()
	page.PageNo, _ = strconv.Atoi(c.DefaultQuery("current", "1"))
	page.PageSize, _ = strconv.Atoi(c.DefaultQuery("size", "10"))
	finder := zorm.NewFinder().Append("SELECT a.id,a.user_id,b.nickname,b.avatar,b.web_site,a.comment_content,a.create_time from")
	finder.Append(structs.TbCommentStructTableName).Append("AS a")
	finder.Append("LEFT JOIN").Append(structs.TbUserInfoStructTableName).Append("AS b")
	finder.Append("ON a.user_id = b.id ")
	finder.Append("WHERE a.article_id=? AND a.is_review =? AND a.is_delete =? AND parent_id is null", articleId, 1, 0).Append("ORDER BY a.create_time ASC")
	err := zorm.Query(c, finder, &data, page)
	if err != nil {
		return bloggo.FailMessage(err.Error())
	}
	likeCountMap, err := bloggo.Hgetall(bloggo.COMMENT_LIKE_COUNT)
	tempMap := map[int]*dto.Comment{}
	var ids []int
	for _, item := range data {
		item.LikeCount, _ = redis.Int(likeCountMap[strconv.Itoa(item.Id)], nil)
		ids = append(ids, item.Id)
		tempMap[item.Id] = item
	}
	var replyList []dto.ReplyDTO
	err = service.FindReplyDTO(c, ids, &replyList, nil)
	if err != nil || len(replyList) == 0 {
		return bloggo.OkData(data)
	}

	for _, item := range replyList {
		item.LikeCount, _ = redis.Int(likeCountMap[strconv.Itoa(item.Id)], nil)
		list := tempMap[item.ParentId]
		list.ReplyDTOList = append(list.ReplyDTOList, item)
	}

	for _, item := range data {
		item.ReplyCount = len(item.ReplyDTOList)
	}

	return bloggo.OkData(data)
}

// PostComment 发表评论
func PostComment(c *gin.Context) *bloggo.R {
	all, err := ioutil.ReadAll(c.Request.Body)
	if err != nil {
		return bloggo.FailMessage(err.Error())
	}
	reqData := dto.PostComment{}
	err = json.Unmarshal(all, &reqData)
	if err != nil {
		return bloggo.FailMessage(err.Error())
	}
	user := bloggo.GetSessionUser()
	userId, _ := strconv.Atoi(user.UserId)
	articleId, _ := strconv.Atoi(reqData.ArticleId)
	//发表评论
	//TODO 评论是否已审核IsReview
	commentStruct := structs.TbCommentStruct{
		UserId:         userId,
		ArticleId:      articleId,
		CommentContent: reqData.CommentContent,
		ReplyUserId:    reqData.ReplyUserId,
		ParentId:       reqData.ParentId,
		CreateTime:     time.Now(),
		UpdateTime:     time.Now(),
		IsDelete:       0,
		IsReview:       1,
	}
	err = service.SaveTbCommentStruct(c, &commentStruct)
	if err != nil {
		return bloggo.FailMessage(err.Error())
	}
	return bloggo.Ok()
}

// CommentLike 点赞评论
func CommentLike(c *gin.Context) *bloggo.R {
	commentId := c.Param("commentId")
	if commentId == "" {
		return bloggo.Fail()
	}
	commentIdBytes := []byte(commentId)
	// 判断是否点赞
	commentLikeKey := bloggo.COMMENT_USER_LIKE + bloggo.GetSessionUser().UserId
	if bloggo.SisMember(commentLikeKey, commentIdBytes) {
		// 点过赞则删除评论id
		bloggo.Srem(commentLikeKey, commentIdBytes)
		// 评论点赞量-1
		bloggo.Hincrby(bloggo.COMMENT_LIKE_COUNT, commentIdBytes, -1)
	} else {
		// 未点赞则增加评论id
		bloggo.Sadd(commentLikeKey, commentIdBytes)
		// 评论点赞量+1
		bloggo.Hincrby(bloggo.COMMENT_LIKE_COUNT, commentIdBytes, 1)
	}
	return bloggo.Ok()
}

// CommentReplies 查询评论下的回复
func CommentReplies(c *gin.Context) *bloggo.R {
	commentId := c.Param("commentId")
	if commentId == "" {
		return bloggo.Fail()
	}
	page := zorm.NewPage()
	page.PageNo, _ = strconv.Atoi(c.DefaultQuery("current", "1"))
	page.PageSize, _ = strconv.Atoi(c.DefaultQuery("size", "5"))
	commentIdInt, err := strconv.Atoi(commentId)
	if err != nil {
		return bloggo.FailMessage(err.Error())
	}
	// 查询评论下的回复
	var replyList []dto.ReplyDTO
	err = service.FindReplyDTO(c, []int{commentIdInt}, &replyList, page)
	if err != nil || len(replyList) == 0 {
		return bloggo.OkData(replyList)
	}
	// 查询redis的评论点赞数据
	likeCountMap, err := bloggo.Hgetall(bloggo.COMMENT_LIKE_COUNT)
	for _, item := range replyList {
		item.LikeCount, _ = redis.Int(likeCountMap[strconv.Itoa(item.Id)], nil)
	}

	return bloggo.OkData(replyList)
}

// AdminComments 评论列表
func AdminComments(c *gin.Context) *bloggo.R {
	page := zorm.NewPage()
	page.PageNo, _ = strconv.Atoi(c.DefaultQuery("current", "1"))
	page.PageSize, _ = strconv.Atoi(c.DefaultQuery("size", "10"))
	isReview := c.DefaultQuery("isReview", "")
	keywords := c.DefaultQuery("keywords", "")
	_type := c.DefaultQuery("type", "") //1.文章 2.友链

	finder := zorm.NewFinder().Append("SELECT a.id,b.avatar,b.nickname,c.nickname AS replyNickname,d.article_title,a.comment_content,a.is_review,a.create_time FROM")
	finder.Append(structs.TbCommentStructTableName).Append("a")
	finder.Append("LEFT JOIN").Append(structs.TbUserInfoStructTableName).Append("b").Append("ON a.user_id = b.id")
	finder.Append("LEFT JOIN").Append(structs.TbUserInfoStructTableName).Append("c").Append("ON a.reply_user_id = c.id")
	finder.Append("LEFT JOIN").Append(structs.TbArticleStructTableName).Append("d").Append("ON a.article_id = d.id")
	finder.Append("WHERE 1=1")
	if len(isReview) > 0 {
		finder.Append("AND a.is_review=?", isReview)
	}
	if len(_type) > 0 { //1.文章 2.友链
		if _type == "1" {
			finder.Append("AND a.article_id IS NOT NULL")
		} else if _type == "2" {
			finder.Append("AND a.article_id IS NULL")
		}
	}
	if len(keywords) > 0 {
		finder.Append("AND b.nickname LIKE ?", "%"+keywords+"%")
	}

	var data []dto.AdminComments
	err := zorm.Query(c, finder, &data, page)
	if err != nil {
		return bloggo.FailMessage(err.Error())
	}
	return bloggo.OkData(gin.H{
		"recordList": data,
		"count":      page.TotalCount,
	})
}

// ReviewComments 评论审核
func ReviewComments(c *gin.Context) *bloggo.R {
	var reqData dto.ReviewCommentDTO
	err := c.ShouldBind(&reqData)
	if err != nil {
		return bloggo.FailMessage(err.Error())
	}
	if len(reqData.IdList) <= 0 {
		return bloggo.Ok()
	}
	finder := zorm.NewFinder().Append("UPDATE").Append(structs.TbCommentStructTableName)
	finder.Append("SET is_review=?,update_time=?", reqData.IsReview, time.Now()).Append("WHERE id IN (?)", reqData.IdList)
	_, err = zorm.Transaction(c, func(c context.Context) (interface{}, error) {
		return zorm.UpdateFinder(c, finder)
	})
	if err != nil {
		return bloggo.FailMessage(err.Error())
	}
	return bloggo.Ok()
}

// DeleteComments 删除评论
func DeleteComments(c *gin.Context) *bloggo.R {
	var idList []int
	err := c.ShouldBind(&idList)
	if err != nil {
		return bloggo.FailMessage(err.Error())
	}
	if len(idList) <= 0 {
		return bloggo.Ok()
	}
	finder := zorm.NewDeleteFinder(structs.TbCommentStructTableName)
	finder.Append("WHERE id IN (?)", idList)
	_, err = zorm.Transaction(c, func(c context.Context) (interface{}, error) {
		return zorm.UpdateFinder(c, finder)
	})
	if err != nil {
		return bloggo.FailMessage(err.Error())
	}
	return bloggo.Ok()
}
